package base.dao;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import app.util.ClassUtil;
import app.util.StringUtil;
import app.util.UUIDUtil;
import base.PageInfo;
import base.category.sys.YesOrNo;

@Service
@Transactional
public class HibernateDao<E>{
	
	@Autowired
	private SessionFactory sessionFactory;
	
	public Session getSession() {
		Session session = sessionFactory.getCurrentSession(); //You must add @Transactional into your @Repository
//		Session session = sessionFactory.openSession();
		return session;
	}

	/**
	 * 返回值为map集合 且为唯一值（只能返回一条数据）
	 * @param sql
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Map<String,Object> queryMapBySql(String sql) {
		SQLQuery query = getSession().createSQLQuery(sql);
		return (Map<String, Object>) query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).uniqueResult();
	}
	
    public Object queryObjectById(String id,Class<?> className) {
    	Object load = getSession().get(className, id);
        return load;
    }
	
	public Object queryObjectByHQL(String hql) {
        Query query = this.getSession().createQuery(hql);
        return query.uniqueResult();
    }
	
	public E mapToEntity(Class<E> objClass,Map<String,Object> map){
		E entity = null;
		return entity;
	}
	
	public E queryEntityById(String id,Class<E> className) {
        E e = (E)getSession().get(className, id);
        return e;
    }
	
	public E queryEntityByHQL(String hql) {
        Query query = this.getSession().createQuery(hql);
        return (E) query.uniqueResult();
    }
	
	/**
	 * 返回值为Object集合 且为唯一值（只能返回一条数据）
	 * @param sql
	 * @param className 
	 * @return
	 */
	public <E> E queryEntityBySql(String sql, Class<E> className) {
		SQLQuery query = getSession().createSQLQuery(sql).addEntity(className);
		return (E)query.uniqueResult();
	}
	
	/**
	 * 返回list集合
	 * @param sql
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Map<String,Object>> queryListBySql(String sql) {
		SQLQuery query = getSession().createSQLQuery(sql);
		return ClassUtil.toHumpNamed(query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list());
	}
	
	/**
	 * 查询sql分页
	 * @param pageInfo
	 * @param sql
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public PageInfo queryPageListBySql(PageInfo pageInfo,String sql) {
		SQLQuery query = getSession().createSQLQuery(sql);
		int size = query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list().size();
		pageInfo.setAllCount(size);//总数
		query.setFirstResult(pageInfo.getStart());
		query.setMaxResults(pageInfo.getPageSize());
		pageInfo.setObjectList(ClassUtil.toHumpNamed(query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list()));
		return pageInfo;
	}

	/**
	 * 保存
	 * @param newInstance
	 */
	public void save(Object newInstance){
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(newInstance.getClass());    
	        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();  
	        
			for (PropertyDescriptor property : propertyDescriptors) {
				Method setter = property.getWriteMethod();
				if (setter != null && "id".equals(property.getName())) {
					setter.invoke(newInstance, UUIDUtil.getUUID());
				} else if (setter != null && "createTime".equals(property.getName())) {
					setter.invoke(newInstance, new Date());
				} else if (setter != null && "isUse".equals(property.getName())) {
					setter.invoke(newInstance, YesOrNo.YES_INT);
				}
			} 
			
		} catch (Exception e) {
		}
		getSession().save(newInstance);
	}
	
	/**
	 * 更新
	 * @param newInstance
	 */
//	public void update(Object newInstance){
//		getSession().update(newInstance);
//	}
	
	/**
	 * 自定义合并更新
	 * @param newInstance
	 */
	public void mergeAndUpdate(Object newInstance){
		
		ClassMetadata md = sessionFactory.getClassMetadata(newInstance.getClass());
	    String idPropertyName = md.getIdentifierPropertyName();
//	    Field declaredField;
	    Object id = null;
		try {
			id = getValue(newInstance, idPropertyName);
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		
		Object entity = getSession().get(newInstance.getClass(), StringUtil.objectToStr(id));
		
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(newInstance.getClass());    
	        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();  
	        
			for (PropertyDescriptor property : propertyDescriptors) {
				Method setter = property.getWriteMethod();
				if (setter != null) {
					if("isUse".equals(property.getName())){
						continue;
					}
					Object value = getValue(newInstance, property.getName())!=null?getValue(newInstance, property.getName()):getValue(entity, property.getName());
					setter.invoke(entity, value);
				}
			} 
		} catch (Exception e) {
		}
		
		getSession().update(entity);
	}

	private Object getValue(Object newInstance, String idPropertyName) throws NoSuchFieldException, IllegalAccessException {
		Field declaredField;
		Object id;
		declaredField = newInstance.getClass().getDeclaredField(idPropertyName);
		declaredField.setAccessible(true);
		id = declaredField.get(newInstance);
		return id;
	}
	
	/**
	 * 删除对象
	 * @param newInstance
	 */
	public void del(Object newInstance){
		getSession().delete(newInstance);
	}
	
	/**
	 * 删除对象
	 * @param newInstance
	 */
	public void delEntity(E entity){
		getSession().delete(entity);
	}
}
